module repository.AnimationRepo;

import std.format;

import d2sqlite3;

import model.Animation;
import model.AnimationVlink;
import utils.ConstValue;

// 动漫仓储类
class AnimationRepo
{
    Database db;
    this ()
    {
        db = Database(Const.connStr);
    }

    ~this ()
    {
        db.close();
    }

    /** 
     * 添加动漫
     * Params:
     *   animation   Animation    Animation实例
     * Returns: bool
     */
    bool addAnimation (Animation animation)
    {
        Statement statement1 = db.prepare("SELECT a.id FROM animation a WHERE a.id = :id LIMIT 1;");
        statement1.bind(":id", animation.id);
        ResultRange res = statement1.execute();
        if (!res.empty)
        {
            return true;
        }

        Statement statement2 = db.prepare("INSERT INTO animation (id, name, url, category, region, year, actors, director, intro, img, comment) VALUES (:id, :name, :url, :category, :region, :year, :actors, :director, :intro, :img, :comment)");
        statement2.bindAll(animation.id, animation.name, animation.url, animation.category, animation.region, animation.year, animation
                .actors, animation.director, animation.intro, animation.img, animation.comment);
        statement2.execute();
        return db.changes > 0;
    }

    /** 
     * 批量添加动漫
     * Params:
     *   animationList   Animation[]    待添加的动漫列表
     * Returns: bool
     */
    bool addAnimationBatch (Animation[] animationList)
    {
        import std.format : format;

        auto total = animationList.length;
        string sql = "INSERT INTO animation (id, name, url, category, region, year, actors, director, intro, img, comment) VALUES ";
        string sqlLeft;
        foreach (a; animationList)
        {
            sqlLeft = format(`("%s","%s","%s","%s","%s",%d,"%s","%s","%s","%s","%s")`, a.id, a.name, a.url, a
                    .category, a.region, a.year, a.actors, a.director, a.intro, a.img, a.comment);
            sql ~= sqlLeft;
        }
        sql ~= ";";

        db.execute(sql);
        int ch = db.changes;
        if (0 < ch && ch <= total)
        {
            return true;
        }
        return false;
    }

    /** 
     * 删除动漫
     * Params:
     *   animationId  =  `string`  =  id值
     * Returns: bool
     */
    bool removeAnimation (string animationId)
    {
        Statement statement = db.prepare("DELETE FROM animation WHERE id=:id");
        statement.bind(":id", animationId);
        statement.execute();
        return db.changes > 0;
    }

    /** 
    * 更新动漫信息
    * Params:
    *   animationId  =  string    id值
    *   animation  =  Animation    Animation实例
    * Returns: bool
    */
    bool updateAnimation (string animationId, Animation animation)
    {
        import std.conv : to;
        import std.digest : toHexString;
        import std.digest.md : md5Of;

        string newid = to!string(toHexString(md5Of(animation.name)));

        Statement statement = db.prepare("UPDATE animation SET id=:newid, name=:name, url=:url, category=:category, region=:region, year=:year, actors=:actors, director=:director, intro=:intro, img=:img, comment=:comment WHERE id=:id");
        statement.bindAll(newid, animation.name, animation.url, animation.category, animation.region, animation.year, animation
                .actors, animation
                .director, animation.intro, animation.img, animation.comment, animationId);
        statement.execute();
        return db.changes > 0;
    }

    /** 
     * 获取动漫列表数据
     * Returns: Animation[]
     */
    Animation[] getAnimationList ()
    {
        ResultRange results = db.execute("SELECT id, name, url, category, region, year, actors, director, intro, img, comment FROM animation ORDER BY year DESC;");

        Animation[] animationList = [];
        if (results.empty)
        {
            return animationList;
        }
        foreach (Row row; results)
        {
            auto id = row["id"].as!string;
            auto name = row["name"].as!string;
            auto url = row["url"].as!string;
            auto category = row["category"].as!string;
            auto region = row["region"].as!string;
            auto year = row["year"].as!uint;
            auto actors = row["actors"].as!string;
            auto director = row["director"].as!string;
            auto intro = row["intro"].as!string;
            auto img = row["img"].as!string;
            auto comment = row["comment"].as!string;

            animationList ~= new Animation(id, name, url, category, region, year, actors, director, intro, img, comment);
        }

        return animationList;
    }

    /** 
     * 分页获取动漫列表数据
     * Params:
     *   pageSize    uint    页大小
     *   pageNum    uint    页码
     * Returns: Animation[]
     */
    Animation[] getAnimationList (uint pageSize, uint pageNum)
    {
        if (pageSize <= 4)
        {
            pageSize = 8;
        }
        if (pageNum <= 0)
        {
            pageNum = 1;
        }
        uint offset = (pageNum - 1) * pageSize;
        Statement statement = db.prepare("SELECT id, name, url, category, region, year, actors, director, intro, img, comment FROM animation as a ORDER BY a.year DESC LIMIT :pageSize OFFSET :offset;");
        statement.bindAll(pageSize, offset);
        ResultRange results = statement.execute();
        scope (exit)
        {
            statement.reset();
        }

        Animation[] animationList = [];
        if (results.empty)
        {
            return animationList;
        }
        foreach (Row row; results)
        {
            auto id = row["id"].as!string;
            auto name = row["name"].as!string;
            auto url = row["url"].as!string;
            auto category = row["category"].as!string;
            auto region = row["region"].as!string;
            auto year = row["year"].as!uint;
            auto actors = row["actors"].as!string;
            auto director = row["director"].as!string;
            auto intro = row["intro"].as!string;
            auto img = row["img"].as!string;
            auto comment = row["comment"].as!string;

            animationList ~= new Animation(id, name, url, category, region, year, actors, director, intro, img, comment);
        }

        return animationList;
    }

    /** 
     * 获取总记录数
     * Returns: uint
     */
    uint getTotalCount ()
    {
        uint total = db.execute("SELECT COUNT(id) FROM animation;").oneValue!uint;
        return total;
    }

    /** 
     * 获取一个动漫
     * Params:
     *   animationId    string    id值
     * Returns: Animation
     */
    Animation getOneAnimation (string animationId)
    {
        Statement statement = db.prepare(
            "SELECT id, name, url, category, region, year, actors, director, intro, img, comment FROM animation WHERE id=:id LIMIT 1");

        statement.bind(":id", animationId);
        ResultRange results = statement.execute();
        scope (exit)
        {
            statement.reset();
        }

        if (results.empty)
        {
            return null;
        }
        auto row = results.front;
        auto id = row["id"].as!string;
        auto name = row["name"].as!string;
        auto url = row["url"].as!string;
        auto category = row["category"].as!string;
        auto region = row["region"].as!string;
        auto year = row["year"].as!uint;
        auto actors = row["actors"].as!string;
        auto director = row["director"].as!string;
        auto intro = row["intro"].as!string;
        auto img = row["img"].as!string;
        auto comment = row["comment"].as!string;

        return new Animation(id, name, url, category, region, year, actors, director, intro, img, comment);
    }

    /** 
     * 获取某个动漫的集数链接
     * Params:
     *   animationId    string    动漫id值
     * Returns: AnimationVlink[]
     */
    AnimationVlink[] getAnimationVideoLinks (string animationId)
    {
        Statement statement = db.prepare(
            "SELECT id, name, url, real_url FROM animation_vlinks WHERE animation_id=:id;");
        statement.bind(":id", animationId);
        ResultRange results = statement.execute();

        scope (exit)
        {
            statement.reset();
        }

        AnimationVlink[] list = [];
        if (results.empty)
        {
            return list;
        }

        foreach (Row row; results)
        {
            auto id = row["id"].as!uint;
            auto name = row["name"].as!string;
            auto url = row["url"].as!string;
            auto real_url = row["real_url"].as!string;

            list ~= new AnimationVlink(id, name, url, real_url);
        }

        return list;
    }

    /** 
     * 获取动漫全部年份
     * Returns: uint[]
     */
    uint[] getAnimationYears ()
    {
        uint[] years = [];
        ResultRange results = db.execute("SELECT DISTINCT year FROM animation;");
        if (results.empty)
        {
            return years;
        }
        foreach (Row row; results)
        {
            uint year = row["year"].as!uint;
            years ~= year;
        }

        return years;
    }

    /** 
     * 写评语
     * Params:
     *   id = string
     *   comment = string
     * Returns: bool
     */
    bool doComment (string id, string comment)
    {
        Statement statement = db.prepare("UPDATE animation SET comment=:comment WHERE id=:id");
        statement.bind(":comment", comment);
        statement.bind(":id", id);
        statement.execute();
        return db.changes > 0;
    }
}
